﻿using UnityEngine.Assertions;

namespace System {

    public sealed class RandomF64 : IRandom {

        private ulong m_Seed = 1;

        public RandomF64(ulong seed) {
            m_Seed = seed;
        }

        private ulong DoNext(ulong max) => DoNext() % max;
        private ulong DoNext() {
            m_Seed = m_Seed * 1103515245 + 12345;
            return m_Seed / 65536;
        }

        int IRandom.Next(int max) => Next(F64.From(max)).Int;
        public F64 Next(F64 max) {
            var umax = BitConverter.ToUInt64(BitConverter.GetBytes(max.Raw), 0);
            var value = BitConverter.ToInt64(BitConverter.GetBytes(DoNext(umax)), 0);
            return F64.FromRaw(value);
        }

        public F64 Next() {
            var value = BitConverter.ToInt64(BitConverter.GetBytes(DoNext()), 0);
            return F64.FromRaw(value);
        }

        public F64 Next(F64 min, F64 max) {
            var umax = BitConverter.ToUInt64(BitConverter.GetBytes(max.Raw), 0);
            var umin = BitConverter.ToUInt64(BitConverter.GetBytes(min.Raw), 0);

            Assert.IsTrue(umin <= umax, $"{nameof(min)} cannot be greater than {nameof(max)}.");

            var value = BitConverter.ToInt64(BitConverter.GetBytes(DoNext(umax - umin)), 0);
            return F64.FromRaw(value + min.Raw);
        }
    }
}

